"""
增强版模拟退火算法实现模块

模拟退火算法是一种全局优化算法，用于在大的搜索空间中寻找全局最优解。

增强版模拟退火算法包含以下改进：
1. 自适应温度调整
2. 多起点搜索
3. 记忆机制
4. 重启策略
5. 局部搜索增强
"""

import random
import math
import logging
from datetime import datetime
import copy


class EnhancedSimulatedAnnealing:
    """增强版模拟退火算法实现"""

    def __init__(
        self,
        initial_temperature=200.0,
        cooling_rate=0.95,
        min_temperature=0.01,
        max_iterations=1000,
        max_no_improvement=50,
        restart_temperature=500.0,
        restart_threshold=0.01,
        memory_size=10,
        num_starts=3,
        local_search_prob=0.1,
    ):
        """初始化增强版模拟退火算法

        Args:
            initial_temperature: 初始温度
            cooling_rate: 冷却率
            min_temperature: 最小温度，低于此温度时停止搜索
            max_iterations: 最大迭代次数
            max_no_improvement: 最大无改进次数，超过此次数时重启
            restart_temperature: 重启时的温度
            restart_threshold: 重启阈值，当温度低于此值时考虑重启
            memory_size: 记忆库大小，记录最优解的数量
            num_starts: 多起点搜索的起点数量
            local_search_prob: 局部搜索概率
        """
        self.initial_temperature = initial_temperature
        self.cooling_rate = cooling_rate
        self.min_temperature = min_temperature
        self.max_iterations = max_iterations
        self.max_no_improvement = max_no_improvement
        self.restart_temperature = restart_temperature
        self.restart_threshold = restart_threshold
        self.memory_size = memory_size
        self.num_starts = num_starts
        self.local_search_prob = local_search_prob
        self.logger = logging.getLogger(__name__)

    def optimize(
        self,
        initial_solution,
        evaluate_func,
        generate_neighbor_func,
        local_search_func=None,
        context=None,
    ):
        """使用增强版模拟退火算法优化解决方案

        Args:
            initial_solution: 初始解决方案
            evaluate_func: 评估函数，接收一个解决方案并返回适应度值
            generate_neighbor_func: 生成邻域解的函数，接收一个解决方案和上下文
            local_search_func: 局部搜索函数，接收一个解决方案和上下文并返回改进的解决方案
            context: 上下文信息，传递给generate_neighbor_func和local_search_func

        Returns:
            优化后的解决方案
        """
        self.logger.info("开始使用增强版模拟退火算法优化解决方案...")
        start_time = datetime.now()

        # 多起点搜索
        best_solutions = []
        for start in range(self.num_starts):
            self.logger.info(f"开始第 {start+1}/{self.num_starts} 次搜索...")

            # 生成不同的起点
            if start == 0:
                current_solution = initial_solution
            else:
                # 对初始解进行随机扰动
                current_solution = generate_neighbor_func(initial_solution, context)
                for _ in range(10):  # 多次扰动，确保起点足够分散
                    current_solution = generate_neighbor_func(current_solution, context)

            # 评估初始解
            current_fitness = evaluate_func(current_solution)

            # 初始化最佳解
            best_solution = copy.deepcopy(current_solution)
            best_fitness = current_fitness

            # 初始化温度
            temperature = self.initial_temperature

            # 初始化记忆库
            memory = []

            # 初始化无改进计数
            no_improvement_count = 0

            # 模拟退火主循环
            iteration = 0
            while (
                iteration < self.max_iterations and temperature > self.min_temperature
            ):
                # 生成邻域解
                neighbor = generate_neighbor_func(current_solution, context)

                # 局部搜索
                if local_search_func and random.random() < self.local_search_prob:
                    neighbor = local_search_func(neighbor, context)

                # 评估邻域解
                neighbor_fitness = evaluate_func(neighbor)

                # 计算适应度差异
                delta = neighbor_fitness - current_fitness

                # 接受准则
                if delta > 0 or random.random() < math.exp(delta / temperature):
                    current_solution = copy.deepcopy(neighbor)
                    current_fitness = neighbor_fitness

                    # 更新最佳解
                    if current_fitness > best_fitness:
                        best_solution = copy.deepcopy(current_solution)
                        best_fitness = current_fitness
                        no_improvement_count = 0

                        # 更新记忆库
                        memory.append((best_solution, best_fitness))
                        if len(memory) > self.memory_size:
                            memory.sort(key=lambda x: x[1], reverse=True)
                            memory = memory[: self.memory_size]

                        self.logger.info(
                            f"第 {iteration} 次迭代发现更好的解，适应度: {best_fitness}"
                        )
                    else:
                        no_improvement_count += 1
                else:
                    no_improvement_count += 1

                # 重启策略
                if (
                    no_improvement_count >= self.max_no_improvement
                    and temperature < self.restart_threshold
                ):
                    self.logger.info(
                        f"连续 {no_improvement_count} 次没有改进，温度为 {temperature:.4f}，执行重启"
                    )

                    # 从记忆库中选择一个解作为新的起点
                    if memory:
                        memory.sort(key=lambda x: x[1], reverse=True)
                        current_solution, current_fitness = memory[0]

                    # 重置温度
                    temperature = self.restart_temperature
                    no_improvement_count = 0

                # 冷却
                temperature *= self.cooling_rate

                # 自适应温度调整
                if no_improvement_count > self.max_no_improvement // 2:
                    # 如果长时间没有改进，提高温度以增加探索
                    temperature = min(temperature * 1.5, self.restart_temperature)

                # 每100次迭代输出一次日志
                if iteration % 100 == 0:
                    self.logger.info(
                        f"第 {iteration} 次迭代，当前适应度: {current_fitness}，最佳适应度: {best_fitness}，温度: {temperature:.4f}"
                    )

                iteration += 1

            self.logger.info(
                f"第 {start+1}/{self.num_starts} 次搜索完成，最佳适应度: {best_fitness}"
            )
            best_solutions.append((best_solution, best_fitness))

        # 从多次搜索中选择最佳解
        best_solutions.sort(key=lambda x: x[1], reverse=True)
        final_solution, final_fitness = best_solutions[0]

        end_time = datetime.now()
        optimization_time = (end_time - start_time).total_seconds()
        self.logger.info(
            f"增强版模拟退火算法优化完成，耗时 {optimization_time:.2f} 秒，最终适应度: {final_fitness}"
        )

        return final_solution
